// desc: libevent demo simple server

#include <iostream>
#include <string.h>
#include <errno.h>
#ifndef _WIN32
#include <signal.h>
#endif // !_WIN32

#include "event.h"

#define SERVER_PORT 8000

// 客户端数据读取事件
void client_cb(evutil_socket_t s, short what, void *arg)
{
    // 水平触发LT：只要有数据没有处理，就会一直触发
    // 边沿触发ET：只处理一次，不管数据是否处理完
    event *ev = (event*)arg;

    // 判断超时
    if (what & EV_TIMEOUT) {
        // 需要清理event
        std::cout << "timeout" << std::endl;
        event_free(ev);
        evutil_closesocket(s);
        return;
    }

    // 这是是为了测试，每次只读取4个数据，实际使用中不会这样用的
    char buf[5] = { 0 };
    int len = recv(s, buf, sizeof(buf) - 1, 0);
    if (len > 0) {
        std::cout << buf << std::endl;
        send(s, "OK", 2, 0);
    }
    else {
        // 需要清理event
        std::cout << "event_free" << std::endl;
        event_free(ev);
        evutil_closesocket(s);
    }
}

// 接收连接的回调函数
void listen_cb(evutil_socket_t s, short what, void *arg)
{
    std::cout << "listen_cb" << std::endl;

    // 读取连接信息
    sockaddr_in sin;
    socklen_t len = sizeof(sin);
    evutil_socket_t client = accept(s, (sockaddr*)&sin, &len);

    char ip[16] = { 0 };
    evutil_inet_ntop(AF_INET, &sin.sin_addr, ip, sizeof(ip) - 1);
    std::cout << "client ip: " << ip << ":" << ntohs(sin.sin_port) << std::endl;

    // 客户端数据读取事件
    event_base *base = (event_base*)arg;
    // 水平触发
    //event* ev = event_new(base, client, EV_READ | EV_PERSIST, client_cb, event_self_cbarg());
    // 边沿触发，Windows上无效
    event* ev = event_new(base, client, EV_READ | EV_PERSIST | EV_ET, client_cb, event_self_cbarg());
    timeval tv = { 10, 0 };  // 10秒超时
    event_add(ev, &tv);
}

int main(int argc, char* argv[])
{
#ifdef _WIN32
    // 初始化socket库
    WSADATA wsa;
    WSAStartup(MAKEWORD(2, 2), &wsa);
#else
    // 忽略管道信号，因为发送数据给已关闭的socket会生成SIGPIPE信号，导致进程退出
    if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
        return -1;
#endif

    std::cout << "libevent echo server test" << std::endl;
    // 创建libevent上下文
    event_base *base = event_base_new();
    if (!base) {
        std::cout << "event_base_new failed" << std::endl;
        return -1;
    }
    std::cout << "event_base_new success" << std::endl;

    // 创建 socket
    evutil_socket_t sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock <= 0) {
        std::cout << "create socket error: " << strerror(errno) << std::endl;
        return -1;
    }

    // 设置非阻塞和地址复用
    evutil_make_socket_nonblocking(sock);
    evutil_make_listen_socket_reuseable(sock);

    // 绑定IP和端口
    struct sockaddr_in sin;
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(SERVER_PORT);
    int ret = bind(sock, (sockaddr*)&sin, sizeof(sin));
    if (ret != 0) {
        std::cout << "bind socket error: " << strerror(errno) << std::endl;
        return -1;
    }

    // 开始监听，建立10个连接的缓存
    listen(sock, 10);

    // 创建监听事件，并添加到libevent中
    event* ev = event_new(base, sock, EV_READ | EV_PERSIST, listen_cb, base);
    event_add(ev, 0);

    // 事件分发处理
    event_base_dispatch(base);

    // 释放资源
    if (ev) event_free(ev);
    event_base_free(base);

#ifdef _WIN32
    WSACleanup();
#endif

    return 0;
}
